package lockmanager;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;

//using non-blocking algorithm, atomic and compareAndSet.

public class ResourcePoolNonBlocking implements ResourcePool{
	
	private List<Object> resourceList;
	
	//0 means resource node is empty,available for put
	//1 means resource node is not empty, available for get
	//2 means resource node is updating by put
	//3 means resource node is updating by get
	private List<AtomicInteger> flagList;
	
	private int length = 10;
	private int compete = 5;
	private Semaphore available = new Semaphore(length+compete,false);

	
	public ResourcePoolNonBlocking(){
		
		resourceList = new ArrayList<Object>();
		flagList = new ArrayList<AtomicInteger>();
		
		for(int i=0;i<length;i++){
			resourceList.add(i,i+1);
		}
		
		for(int i=0;i<length;i++){
			AtomicInteger element = new AtomicInteger(1);
			flagList.add(i,element);
		}
		
	}
	
	//This is used for using other resource.
	ResourcePoolNonBlocking(List<Object> resource,int length){
		
		this.resourceList = resource;
		this.length = length;
		flagList = new ArrayList<AtomicInteger>();
		for(int i=0;i<length;i++){
			AtomicInteger element = new AtomicInteger(1);
			flagList.add(i,element);
		}
		
	}
		

	@Override
	public int getPoolSize() {
		return this.length;
	}

	@Override
	public void setResurceList(List<? extends Object> resource) {
		this.resourceList = (List<Object>) resource;
	}

	@Override
	public List<? extends Object> getResouceList() {
		return this.resourceList;
	}
	
	@Override
	public int getContentionSize() {
		return this.compete;
	}

	@Override
	public int getCapacity() {
		return (compete+length);
	}
	

	/**
	 * To get one resource.
	 */
	@Override
	public Object get() {

	//	try {
		//	available.acquire();
		//} catch (InterruptedException e) {
		//	e.printStackTrace();
		//}

		Object element = null;
		
		while(element == null && !Thread.interrupted()){
			
			int i = 0;
			while(i < length){
				if(flagList.get(i).compareAndSet(1, 3)){
					element = resourceList.set(i,null);
					flagList.get(i).compareAndSet(3, 0);
					break;
				}
				i++;
			}
		}
		return element;
	}

	@Override
	public boolean put(Object element) {
		
		boolean putted = false;
		
		while(!putted && !Thread.interrupted()){
			
			int i = 0;
			while (i < length) {
				if (flagList.get(i).compareAndSet(0, 2)) {
					resourceList.set(i, element);
					flagList.get(i).compareAndSet(2, 1);
					break;
				}
				i++;
			}

			if (i < length)
				putted = true;
			else
				putted = false;
			
		}
		
	//	available.release();
		return true;
	}

	
	

}
